package com.lamda.zhekou.manager.impl;

import com.lamda.zhekou.controller.CommandController;
import com.lamda.zhekou.dao.*;
import com.lamda.zhekou.exception.ZheKouException;
import com.lamda.zhekou.manager.PageModel;
import com.lamda.zhekou.manager.ServerHostManager;
import com.lamda.zhekou.manager.UserManager;
import com.lamda.zhekou.model.*;
import com.lamda.zhekou.utils.HttpUtils;
import com.lamda.zhekou.utils.SMSUtil;
import com.lamda.zhekou.vo.HostVo;
import com.lamda.zhekou.vo.IncomeTotalVo;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;

/**
 * Created by MJiao on 15/8/16.
 */
@Service
public class ServerHostManagerImpl implements ServerHostManager {

    private static final Logger LOGGER = LoggerFactory.getLogger(ServerHostManagerImpl.class);
    @Autowired
    private ServerHostDao serverHostDao;
    @Autowired
    private VPSDao vpsDao;
    @Autowired
    private UserVpsDao userVpsDao;
    @Autowired
    private UserManager userManager;
    @Autowired
    private VpsBuyRecordDao vpsBuyRecordDao;

    @Autowired
    private CommandController commandController;

    @Autowired
    private ExpireWarningRecordDao expireWarningRecordDao;

    @Override
    public void registerVps(Long operatorId, String userEmail, Long hostId, Long vpsId, Timestamp expireTime,int type,float rmb) throws ZheKouException {
        User customer = this.userManager.getUsersByFyEmail(userEmail);
        if (customer == null) {
            throw new ZheKouException("您要操作的用户不存在!");
        }
        // 1. 第一步检查vps是否已经被分配
//
        UserVps tUserVps = this.userVpsDao.findUserVpsByUserIdAndVpsId(customer.getId(), vpsId);
        if (tUserVps != null) {
            throw new ZheKouException("vps已经被分别给其他用户,不能重复分配");
        }
        VPS vps = this.vpsDao.findById(vpsId);
        if (vps == null) {
            throw new ZheKouException("您要分配的vps不存在或者已被释放!");
        }

        /**
         * 保存user与vps的映射关系
         */
        UserVps userVps = new UserVps();
        userVps.setCreateTime(new Timestamp(System.currentTimeMillis()));
        userVps.setRmb(rmb);
        userVps.setExpireTime(expireTime);
        userVps.setUser(customer);
        userVps.setVps(vps);

        LOGGER.info("*******************************");
        this.userVpsDao.persist(userVps);

        /**
         * 保存登陆记录
         */
        User operator = this.userManager.findUserById(operatorId);        //登记者
        VpsBuyRecord vpsBuyRecord = new VpsBuyRecord();
        vpsBuyRecord.setCreateTime(new Timestamp(System.currentTimeMillis()));
        vpsBuyRecord.setCustomer(customer);
        if(type==1){
            vpsBuyRecord.setOperatorCode(VpsBuyRecord.OperatorCode.TRYOUT);//试用
        }else {
            vpsBuyRecord.setOperatorCode(VpsBuyRecord.OperatorCode.HIRE);//租用
        }

        vpsBuyRecord.setSeller(operator);
        vpsBuyRecord.setRmb(rmb);
        vpsBuyRecord.setVps(vps);
        this.vpsBuyRecordDao.persist(vpsBuyRecord);
        LOGGER.info("#################################");
    }

    @Override
    public List<ServerHost> getAllServerHosts() {
        return this.serverHostDao.findAll();
    }

    @Override
    public ServerHost getServerHostById(Long serverHostId) {
        return this.serverHostDao.findById(serverHostId);
    }

    @Override
    public List<UserVps> getUserVpsListBy(Set<VPS> vpsSet) {
        return this.userVpsDao.getUserVpsListBy(vpsSet);
    }

    @Override
    public List<UserVps> findUserVpsListByUserId(Long userId) {
        return this.userVpsDao.findUserVpsListByUserId(userId);
    }

    @Override
    public List<VpsBuyRecord> getAllVpsBuyRecordList() {
        return this.vpsBuyRecordDao.findAll();
    }

    @Override
    public List<IncomeTotalVo> getIncomeTotalList() {

        List<IncomeTotalVo> incomeTotalList = this.vpsBuyRecordDao.getIncomeTotalList();
        Collections.sort(incomeTotalList, new Comparator<IncomeTotalVo>() {
            @Override
            public int compare(IncomeTotalVo o1, IncomeTotalVo o2) {
                return Float.valueOf(o1.getRmb()).compareTo(Float.valueOf(o2.getRmb()));
            }
        });
        return incomeTotalList;
    }

    @Override
    public VPS getVpsByVpsId(Long vpsId) {
        return this.vpsDao.findById(vpsId);
    }

    @Override
    public void checkWarning() {
        //查询剩余3天到7天的服务器
        List<UserVps> leftFromThreeToSevenDaysVpsList = this.userVpsDao.getLeftDaysVpsList(3, 7);

        //查询剩余1天到3天的服务器
        List<UserVps> leftFromOneToThreeDaysVpsList = this.userVpsDao.getLeftDaysVpsList(1, 3);

        //查询今天到期的服务器
        List<UserVps> leftFromLessThanOneVpsList = this.userVpsDao.getLeftDaysVpsList(0, 1);


        for (UserVps userVps : leftFromThreeToSevenDaysVpsList) {
            //判断是否已经3-7天报警
            ExpireWarningRecord.WarningType warningType = ExpireWarningRecord.WarningType.SevenDay;

            processWarning(userVps, warningType);

        }

        for (UserVps userVps : leftFromOneToThreeDaysVpsList) {
            //判断是否已经1-3天报警
            ExpireWarningRecord.WarningType warningType = ExpireWarningRecord.WarningType.ThreeDay;

            processWarning(userVps, warningType);

        }
        for (UserVps userVps : leftFromLessThanOneVpsList) {
            //判断是否已经0-1天报警
            ExpireWarningRecord.WarningType warningType = ExpireWarningRecord.WarningType.OneDay;

            processWarning(userVps, warningType);
        }
        //
        Double totalIncome = this.vpsBuyRecordDao.getIncomeTotal();
        HttpUtils.sendMessage(totalIncome);

    }

    @Override
    public  void checkExpired(){
        //查询已经到期的服务器
        List<UserVps>expiredVpsList = this.userVpsDao.getExpiredVpsList();
        for (UserVps userVps : expiredVpsList) {
            //发送关机指令
            commandController.userVpsPowerOff(userVps.getVps().getId());
        }
    }

    @Override
    public UserVps getUserVpsByUVId(Long userVpsId) {
        return this.userVpsDao.findById(userVpsId);
    }

    /**
     * vps续费
     *
     * @param operatorUserId
     * @param userVpsId
     * @param expireTime
     * @param rmb
     * @throws ZheKouException
     */
    @Override
    public void renewVps(Long operatorUserId, Long userVpsId, Timestamp expireTime, float rmb) throws ZheKouException {
        UserVps userVps = this.userVpsDao.findById(userVpsId);
        userVps.setExpireTime(expireTime);
        userVps.setRmb(rmb);
        //更新续费时间
        userVps.setRenewTime(new Timestamp(System.currentTimeMillis()));

        //续费记录
        VpsBuyRecord vpsBuyRecord = new VpsBuyRecord();
        vpsBuyRecord.setRmb(rmb);
        vpsBuyRecord.setCustomer(userVps.getUser());
        vpsBuyRecord.setOperatorCode(VpsBuyRecord.OperatorCode.Renew);
        vpsBuyRecord.setSeller(this.userManager.findUserById(operatorUserId));
        vpsBuyRecord.setVps(userVps.getVps());
        vpsBuyRecord.setCreateTime(new Timestamp(System.currentTimeMillis()));

        this.vpsBuyRecordDao.persist(vpsBuyRecord);
    }

    /**
     * 暂停用户的vps
     *
     * @param operatorUserId
     * @param userVpsId
     */
    @Override
    public void disableUserVps(Long operatorUserId, Long userVpsId) throws ZheKouException {
        UserVps userVps = this.userVpsDao.findById(userVpsId);

        long now = System.currentTimeMillis();
        //使用结束时间
        long endTime = userVps.getExpireTime().getTime();
        //使用开始时间
        long startTime = userVps.getCreateTime().getTime();
        //开始为续费时间或者购买时间
        if (userVps.getRenewTime() != null) {
            startTime = userVps.getRenewTime().getTime();
        }

        float delta = 0;

        //只要大于1天以上的才进行计费
        if (now - startTime < 1000 * 24 * 60 * 60) {
            delta = userVps.getRmb() * (-1);
        } else {
            //总的购买时间(单位:毫秒)
            long buyedTime = endTime - startTime;
            //剩余时间
            long leftTime = endTime - now;
            //单价
            float rmbPerMilllis = userVps.getRmb() / buyedTime;

            delta = leftTime * rmbPerMilllis * (-1);
        }

        this.userVpsDao.delete(userVpsId);

        //停用记录
        VpsBuyRecord vpsBuyRecord = new VpsBuyRecord();
        vpsBuyRecord.setRmb(delta);
        vpsBuyRecord.setCustomer(userVps.getUser());
        vpsBuyRecord.setOperatorCode(VpsBuyRecord.OperatorCode.Disable);
        vpsBuyRecord.setSeller(this.userManager.findUserById(operatorUserId));
        vpsBuyRecord.setVps(userVps.getVps());
        vpsBuyRecord.setCreateTime(new Timestamp(System.currentTimeMillis()));

        this.vpsBuyRecordDao.persist(vpsBuyRecord);
    }

    /**
     * 初始化vps(将已经过期的VPS)
     *
     * @param operatorUserId
     * @param userVpsId
     */
    @Override
    public void doInitVPS(Long operatorUserId, Long userVpsId) throws ZheKouException {
        UserVps userVps = this.userVpsDao.findById(userVpsId);
        this.userVpsDao.delete(userVpsId);

        //停用记录
        VpsBuyRecord vpsBuyRecord = new VpsBuyRecord();
        vpsBuyRecord.setRmb(0);
        vpsBuyRecord.setCustomer(userVps.getUser());
        vpsBuyRecord.setOperatorCode(VpsBuyRecord.OperatorCode.Init);
        vpsBuyRecord.setSeller(this.userManager.findUserById(operatorUserId));
        vpsBuyRecord.setVps(userVps.getVps());
        vpsBuyRecord.setCreateTime(new Timestamp(System.currentTimeMillis()));

        this.vpsBuyRecordDao.persist(vpsBuyRecord);
    }


    /**
     * 查询指定时间范围内的管理的流水情况
     *
     *0 @param startTimestamp
     * @param endTimestamp
     * @return
     */
    @Override
    public List<IncomeTotalVo> getIncomeTotalList(Timestamp startTimestamp, Timestamp endTimestamp) {
        return this.vpsBuyRecordDao.getIncomeTotalList(startTimestamp, endTimestamp);
    }

    /**
     * 查询指定时间范围内的购买记录
     *
     * @param hostId
     * @param startTimestamp
     * @param endTimestamp
     * @return
     */
    @Override
    public List<VpsBuyRecord> findVpsBuyRecords(Long hostId, Timestamp startTimestamp, Timestamp endTimestamp) {
        ServerHost serverHost = this.serverHostDao.findById(hostId);
        return this.vpsBuyRecordDao.findVpsBuyRecords(serverHost.getVpsSet(), startTimestamp, endTimestamp);
    }

    @Override
    public List<VpsBuyRecord> findVpsSellRecords(Long hostId, Timestamp startTimestamp, Timestamp endTimestamp) {
        ServerHost serverHost = this.serverHostDao.findById(hostId);
        return this.vpsBuyRecordDao.findVpsSellRecords(serverHost.getVpsSet(), startTimestamp, endTimestamp);
    }

    /**
     * 查询指定时间范围内主机流水情况
     *
     * @param hostId
     * @param startTimestamp
     * @param endTimestamp
     * @return
     */
    @Override
    public List<IncomeTotalVo> getIncomeTotalList(Long hostId, Timestamp startTimestamp, Timestamp endTimestamp) {
        ServerHost serverHost = this.serverHostDao.findById(hostId);
        List<IncomeTotalVo> incomeTotalVos = this.vpsBuyRecordDao.findIncomeTotalList(serverHost.getVpsSet(), startTimestamp, endTimestamp);
        Collections.sort(incomeTotalVos, new Comparator<IncomeTotalVo>() {
            @Override
            public int compare(IncomeTotalVo o1, IncomeTotalVo o2) {

                return -1 * new Float(o1.getRmb()).compareTo(new Float(o2.getRmb()));
            }
        });
        return incomeTotalVos;
    }


    private void processWarning(UserVps userVps, ExpireWarningRecord.WarningType warningType) {
        //判断是否已经向用户发送过报警
        ExpireWarningRecord warningRecord = this.expireWarningRecordDao.judgeHasWarning(warningType, userVps.getVps());
        if (warningRecord != null && warningRecord.isReach()) {
            return;
        }
        boolean isNewWarn = true;
        if (warningRecord != null) {
            isNewWarn = false;
        }
        boolean succ = false;
        switch (warningType) {
            case SevenDay: {
                succ = SMSUtil.sendSevenExpireWarning(Long.parseLong(userVps.getUser().getTelephone()), userVps.getExpireTime());
                break;
            }
            case ThreeDay: {
                succ = SMSUtil.sendThreeDayExpireWarning(Long.parseLong(userVps.getUser().getTelephone()), userVps.getExpireTime());
            }
            break;
            case OneDay: {
                succ = SMSUtil.sendLessOneDayExpireWarning(Long.parseLong(userVps.getUser().getTelephone()));
            }
        }


        ExpireWarningRecord expireWarningRecord = warningRecord != null ? warningRecord : new ExpireWarningRecord();
        expireWarningRecord.setWarningType(ExpireWarningRecord.WarningType.SevenDay);
        expireWarningRecord.setVps(userVps.getVps());
        expireWarningRecord.setReWarningTime(new Timestamp(System.currentTimeMillis()));
        expireWarningRecord.setIsReach(succ);

        if (isNewWarn) {
            this.expireWarningRecordDao.persist(expireWarningRecord);
        } else {
            this.expireWarningRecordDao.update(expireWarningRecord);
        }
    }


    @Override
    public void registerServerHost(ServerHost serverHost) throws ZheKouException {
        ServerHost registeredServerHost = this.fgetServerHostByIp(serverHost.getIp());
        //如果不为空，则说明该主机(Worker已经注册过了)
        if (registeredServerHost != null) {
            //判断主机是否被更改
            if (registeredServerHost.getHostname().equals(serverHost.getHostname())) {
                registeredServerHost.setHostname(serverHost.getHostname());
            }
            //备注可能已被修改
            registeredServerHost.setRemark(serverHost.getRemark());
            //1. 先取出没有注册的vps set
            //1. 主机上新增加的vps 集合subtract
            Collection<VPS> addingVpsCollection = CollectionUtils.subtract(serverHost.getVpsSet(), registeredServerHost.getVpsSet());
            registeredServerHost.getVpsSet().addAll(new HashSet<>(addingVpsCollection));


            //2. 主机上已经不存在的vps， 失效的vps
            Collection<VPS> invalidVpsCollection = CollectionUtils.subtract(registeredServerHost.getVpsSet(), serverHost.getVpsSet());
            for (VPS invalidVps : invalidVpsCollection) {
                invalidVps.setStatus("不存在");
            }

            //3. 主机上存在，并且在主机记录也存在的vps->更新vps状态
            Collection<VPS> intersectionVpsCollection = CollectionUtils.intersection(serverHost.getVpsSet(), registeredServerHost.getVpsSet());
            for (VPS intersectionvps : intersectionVpsCollection) {
                for (VPS registerVps : registeredServerHost.getVpsSet()) {
                    if (registerVps.getVmId().equals(intersectionvps.getVmId())) {
                        registerVps.setStatus(intersectionvps.getStatus());
                        registerVps.setVmName(intersectionvps.getVmName());
                        registerVps.setComputerName(intersectionvps.getComputerName());
                        registerVps.setUptime(intersectionvps.getUptime());
                        registerVps.setWorkerIp(serverHost.getIp());
                        break;
                    }
                }
            }
            for (VPS vps : registeredServerHost.getVpsSet()) {
                vps.setStatusLastRefreshTime(new Timestamp(System.currentTimeMillis()));
                vps.setWorkerIp(serverHost.getIp());
            }
            this.serverHostDao.update(registeredServerHost);
            return;
        }

        for (VPS vps : serverHost.getVpsSet()) {
            vps.setStatusLastRefreshTime(new Timestamp(System.currentTimeMillis()));
            vps.setWorkerIp(serverHost.getIp());
        }
        this.serverHostDao.persist(serverHost);

    }

    @Override
    public void addVPS(Long serverHostId, String name, String status) {

    }


    @Override
    public PageModel<ServerHost> pagingServerHost() {
        return null;
    }

    @Override
    public PageModel<User> paging(int pageNo, int pageSize, boolean asc) {
        return new PageModel<>();
    }

    @Override
    public List<HostVo> getHostsByFilter(String keyWord) {
        List<ServerHost> hosts = this.serverHostDao.getHostsByFilter(keyWord);
        List<HostVo> voList = new ArrayList<>();
        for (ServerHost host : hosts) {
            HostVo hostVo = new HostVo();
            hostVo.setIp(host.getIp());
            hostVo.setName(host.getHostname());
            hostVo.setHostId(host.getId());
            voList.add(hostVo);
        }
        return voList;
    }

    @Override
    public ServerHost fgetServerHostByIp(String ip) {
        return this.serverHostDao.findByParameterAndSingleResult("ip", ip, GenericDao.QueryParameterUtil.EQUAL);
    }

    @Override
    public void update(ServerHost serverHost) {
        this.serverHostDao.update(serverHost);
    }


}
